OS - Lab6实验报告

归档于2025年7月8日。

思考题

6.1

很简单,我们把两个case互换即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdlib.h>  
#include <stdio.h>
#include <unistd.h>

int fildes[2];
char buf[100];
int status;

int main() {
       status = pipe(fildes);
       if (status == -1) return -1;
       switch (fork()) {
               case -1:
                       break;
               case 0:
                       close(fildes[0]); /* 关闭不用的读端 */
                       write(fildes[1], "Hello world\n", 12); /* 向管道中写数据 */
                       close(fildes[1]); /* 写入结束,关闭写端 */
                       exit(EXIT_SUCCESS);
               default:
                       close(fildes[1]); /* 关闭不用的写端 */
                       read(fildes[0], buf, 100); /* 从管道中读数据 */
                       printf("parent-process read:%s",buf); /* 打印读到的数据 */
                       close(fildes[0]); /* 读取结束,关闭读端 */
                       exit(EXIT_SUCCESS);
       }
       return 0;
}

6.2

  • 在我们当前dup()的实现下,我们是先复制文件标识符,再复制文件内容;
  • 如果目标是一个管道,如此就会导致pageref(pipe) > pageref(fd)的取值发生最终取值外的变化;
  • 如果中途被打断,此时执行判断,就会得到错误的判断结果

6.3

在执行syscall时,系统的中断使能会被关闭,计时器发出的中断无效;因此,系统调用过程不会被打断,是原子操作。

与之对比,调用系统的某个模块,比如说,给文件系统进程,提出打开文件的请求,这个步骤不是原子请求。因为这部分,我们采用了微内核设计,将系统调用变成了进程间通信问题。

6.4

  • 调整fdpipe unmap的顺序后,是可以解决这一问题的:在这一操作下,我们总能保证pageref(pipe) > pageref(fd)即不会导致pageref(pipe) == pageref(fd)这一条件语句的取值,在执行过程中出现真实结果外的变化,因此在过程被打断时不会误判。
  • 是会的;在我们当前的实现下,我们是先复制文件标识符,再复制文件内容;如此就会导致pageref(pipe) > pageref(fd)的取值发生真实结果外的变化;调换顺序后,这句话就恒真,也就不会出现中途打断误判的问题了。

6.5

打开文件的过程:

  • 调用open()
  • 分配一个文件描述符;
  • 通过与文件管理进程进行IPC,将文件映射到文件描述符中
  • 建立文件内容的内存映射

读取ELF:

  • 主要由我们已经实现的load_icode()实现
  • load_icode()调用elf_load_seg()加载各个段,并建立内存映射

有关.bss

  • .bss段是与.data.text连在一块空间内的
  • .data.text没有占满的空间,被置0,分给了.bss
  • 另外分配时,使用syscall_mem_alloc()分配,但是不映射到任何内容

6.6

user/init.c中,我们可以找到答案:
Pasted image 20250603152038.png

6.7

都是外部程序,因为我们都要开一个子shell来处理。

cd之所以是内部命令,是因为 cd改变了此时shell的工作目录;如果是外部指令,更改只会对子shell生效;换言之,我们此时交互的shell执行了之后没有任何效果。

6.8

我们需要手动修改一下sh.c中的runcmd(),以在正常spawn时,输出spawn信息。
Pasted image 20250603154613.png

观察运行结果:
Pasted image 20250603154548.png

spawn有两次,对应的均为执行ls.bcat.b的进程;

destroy有四次,对应两次spawn,以及两个fork()出的shell子进程。

难点分析

我认为,是shell的整个执行流程,以及弄清楚shell与先前实现的功能之间如何连接。

在明白了外部功能是由子shell执行以后,以及spawn()函数的调用关系后,剩下的事情就很简单了。

实验体会

OS的实验部分就此结束了。

尽管MOS的实现较为简陋,但在完成各个Lab的实验内容的过程中,我确对理论课所学知识有了更深的理解,也对硬件如何与系统软件构建联系有了初步的认识,收获颇丰。

至于Lab6,其实要完成的功能并不难,难点仍然在于整个执行流程。

原创声明

本报告为本人原创。

作者

LajiPZ

发布于

2025-07-08

更新于

2025-07-09

许可协议

评论